/* 
 * File:   main.cpp
 * Author: nata
 *
 * Created on March 13, 2012, 3:13 PM
 */

#include <cstdlib>
#include <cstdio>
#include <vector>
#include <cstring>
#include <map>
#include <algorithm>
#include <fstream>
#include <opencv/cv.h>
#include <opencv/ml.h>
#include <opencv/cxcore.h>
#include <opencv/highgui.h>
#include <opencv/cvaux.h>

#include "Image.h"
#include "Node.h"
#include "BRIC.h"
#include "Renderer.h"
#include "TreeComparator.h"
#include "PriorityScorer.cpp"
#include "ScoreComparator.h"
/*#include "Scorer2004.cpp"
#include "Scorer2008.cpp"
#include "Scorer2012.cpp"*/

using namespace std;

vector<Image*>* image_list;
vector<IplImage*>* solutions;
Renderer* renderer;
/*Scorer* scorer_2012;
Scorer* scorer_2008;
Scorer* scorer_2004;
Scorer* scorer_priority;*/
BRIC* bric;
int width;
int height;
int alpha;
int beta;
int L;
string file;

IplImage* render_solution(vector<Image*> *images) {
    Node* root = bric->create_tree(images);
    bric->solve(root);
    return renderer->draw_tree(root);
}

IplImage* render_solution(vector<Image*> *images, Orientation orientation) {
    Node* root = bric->create_tree(images);
//    bric->solve(root, orientation);
    return renderer->draw_tree(root);
}

void print_images(vector<Image*> *images) {
    for(int i = 0; i < images->size(); i++) {
        printf("%d %d %.2f %d\n", images->at(i)->get_width(), images->at(i)->get_height(), images->at(i)->get_relative_area(), images->at(i)->get_image());
    }
}

char show_image(IplImage* image) {
    cvShowImage("", image);
    cvMoveWindow("", 0, 0);
    char c = cvWaitKey(0);
    cvDestroyWindow("");
    return c;
}

void show_images(vector<IplImage*> *image_list) {
    printf("Mostrando %d imagem(ns)\n", image_list->size());
    printf("Pressione Q para interromper\n");
    bool run = true;
    int i = 0;
    while(run && i < image_list->size()) {
        stringstream sstream;
        sstream << i + 1 << " / " << image_list->size();
        string title = sstream.str();
        cvShowImage(title.c_str(), image_list->at(i));
        cvMoveWindow(title.c_str(), 0, 0);
        char c = cvWaitKey(0);
        switch(c) {
            case 'q':
                run = false;
                break;
            case 'b':
                if(i > 0)
                    i --;
                break;
            default:
                i ++;
        }
        cvDestroyWindow(title.c_str());
    }
    printf("Fim\n");
}

void load_images(vector<Image*>* images) {
    string file_name = file + "list";
    ifstream f(file_name.c_str(), ios::in);
    if(f) {
        string image_name;
        int priority;
        while(f >> priority >> image_name) {
            string path = file + image_name;
            IplImage *img = cvLoadImage(path.c_str());
            images->push_back(new Image(img->width, img->height, priority, img));
        }
        f.close();
    }
    print_images(image_list);
}

void init() {
    image_list = new vector<Image*>();
    solutions = new vector<IplImage*>();
    width = 800;
    height = 600;
    alpha = 0;
    beta = 5;
    L = 10;
    file = "C:\\Users\\stuart\\Desktop\\image\\daf\\";
/*    scorer_2012 = new Scorer2012(width, height, alpha, beta);
    scorer_2008 = new Scorer2008(width, height, alpha, beta); 
    scorer_2004 = new Scorer2004(width, height, alpha, beta); 
    scorer_priority =  new PriorityScorer(width, height, alpha, beta);*/
    bric = new BRIC(width, height, alpha, beta, L); //, scorer_priority);
    renderer = new Renderer(width, height, alpha, beta);
}

void render_solutions(vector<Image*>* imageList, vector<IplImage*>* solutions) {
    vector<Image*>* images = new vector<Image*>();
    for(int i = 0; i < imageList->size(); i++) {
        images->push_back(imageList->at(i));
        solutions->push_back(render_solution(images));
    }
}

void save(vector<Image*>* _images, string path) {
    vector<Image*> images(*_images);
//    for(int i = 0; i < _images->size(); i++)
//        images.push_back(_images->at(i));
    Node* leaf = new Node(images.back());
    images.pop_back();
    Node* root = bric->create_tree(&images);
    vector<Node*> trees;
    bric->generate_trees(root, root, leaf, &trees);
    printf("%d %d %d\n", trees.size(), _images->size(), images.size());
    for(int i = 0; i < trees.size(); i++) {
        bric->solve(trees.at(i));
        IplImage* rendered = renderer->draw_tree(trees.at(i));
        double score = bric->score(trees.at(i));
        stringstream sstream;
        sstream << path << ((int)(1000000*score)) << ".jpg";
        string title = sstream.str();
        cvSaveImage(title.c_str(), rendered);
    }
}

void save(vector<IplImage*> images, string path) {
    int n = 1;
    for(vector<IplImage*>::iterator it = images.begin(); it != images.end(); it++) {
        stringstream sstream;
        sstream << path << n++ << ".jpg";
        cvSaveImage(sstream.str().c_str(), *it);
    }
}

template <class T>
vector<T>* copy(vector<T>* v, int l) {
    vector<T>* c = new vector<T>();
    for(int i = 0; i < l; i++) {
        c->push_back(v->at(i));
    }
    return c;
}

void run_test() {
    //bric->set_scorer(scorer_priority);
    vector<Image*>* images = new vector<Image*>();
    vector<IplImage*> rendered;
    for(int i = 0; i < image_list->size(); i++) {
        images->push_back(image_list->at(i));
        rendered.push_back(render_solution(images));
    }
    for(int i = 0; i < rendered.size();) {
        switch(show_image(rendered.at(i))) {
            case 'q':
                return;
                break;
            case 'b':
                if(i > 0)
                    i -= 1;
                break;
            case 'n':
                i++;
                break;
            case 's':
                save(copy(images, i + 1), file + "saved\\");
                break;
        }
    }
}

void run_debug() {
    //bric->set_scorer(scorer_priority);
    load_images(image_list);
    vector<Image*>* images = new vector<Image*>();
    vector<IplImage*> rendered;
    for(int i = 0; i < image_list->size(); i++) {
        images->push_back(image_list->at(i));
        rendered.push_back(render_solution(images));
    }
    for(int i = 0; i < rendered.size();) {
        switch(show_image(rendered.at(i))) {
            case 'q':
                return;
                break;
            case 'b':
                if(i > 0)
                    i -= 1;
                break;
            case 'n':
                i++;
                break;
            case 's':
                save(copy(images, i + 1), file + "saved\\");
                break;
            case 'p':
                save(rendered, file + "solved\\");
                break;
        }
    }
}

void normal_run() {
    load_images(image_list);
    render_solutions(image_list, solutions);
    show_images(solutions);
}

void double_solutions() {
    //image_populate(image_list);
    load_images(image_list);
    vector<Image*> images;
    int limit = image_list->size();
    for(int i = 0; i < limit; i++) {
        images.push_back(image_list->at(i));
        solutions->push_back(render_solution(&images, HORIZONTAL));
        solutions->push_back(render_solution(&images, VERTICAL));
    }
    show_images(solutions);
}

void next_leaf_sorted() {
  //  bric->set_scorer(scorer_priority);
//    image_populate(image_list);
    load_images(image_list);
//    Node* leaf = new Node(new Image(600, 600, 2), 5);
    Node* leaf = new Node(image_list->back());
    image_list->pop_back();
    Node* root = bric->create_tree(image_list);
    vector<Node*> trees;
    vector<pair<Node*, double>* > scores;
    bric->generate_trees(root, root, leaf, &trees);
    for(int i = 0; i < trees.size(); i++) {
        bric->solve(trees.at(i));
        scores.push_back(new pair<Node*, double>(trees.at(i), bric->score(trees.at(i))));
    }
    sort(scores.begin(), scores.end(), ScoreComparator());
    solutions->push_back(renderer->draw_tree(root));
    for(int i = 0; i < scores.size(); i++) {
        solutions->push_back(renderer->draw_tree(scores.at(i)->first));
    }
    show_images(solutions);
}

void direct_run() {
    //bric->set_scorer(scorer_priority);
//    image_populate(image_list);
    load_images(image_list);
    Node* root = bric->create_tree(image_list);
    solutions->push_back(renderer->draw_tree(root));
    show_images(solutions);
}

/*void test_scores_all_images() {
    image_populate(image_list);
    vector<Image*> images;
    for(int i = 0; i < image_list->size(); i++) {
        images.push_back(image_list->at(i));
        bric->set_scorer(scorer_2004);
        solutions->push_back(render_solution(&images));        
        bric->set_scorer(scorer_2008);
        solutions->push_back(render_solution(&images));
        bric->set_scorer(scorer_2012);
        solutions->push_back(render_solution(&images));
        bric->set_scorer(scorer_priority);
        solutions->push_back(render_solution(&images));
    }
    show_images(solutions);
}*/

/*void test_scores_finals() {
    image_populate(image_list);
    bric->set_scorer(scorer_2004);
    solutions->push_back(render_solution(image_list));
    bric->set_scorer(scorer_2008);
    solutions->push_back(render_solution(image_list));
    bric->set_scorer(scorer_2012);
    solutions->push_back(render_solution(image_list));
    bric->set_scorer(scorer_priority);
    solutions->push_back(render_solution(image_list));
    show_images(solutions);
}*/

int num_nodes(Node* root) {
    return root->is_leaf() ? 1 : (1 + num_nodes(root->get_left()) + num_nodes(root->get_right()));
}

void test_generate() {
    load_images(image_list);
    vector<Node*> trees;
    vector<Image*> images;
    int num = image_list->size() / 2;
    for(int i = 0; i < num; i++) {
        images.push_back(image_list->at(i));
    }
    Node* root = bric->create_tree(&images);
    Node* leaf = new Node(image_list->at(num));
    bric->generate_trees(root, root, leaf, &trees);
    printf("%d = %d\n", trees.size(), 2*(num_nodes(root)));
}

void test_solver() {
    load_images(image_list);
    vector<Image*> images;
    vector<Node*> trees;
    vector<IplImage*> rendered;
    for(vector<Image*>::iterator it = image_list->begin(); it != image_list->end(); it++) {
        images.push_back(*it);
        trees.push_back(bric->create_tree(&images));
        rendered.push_back(renderer->draw_tree(trees.back()));
    }
    show_images(&rendered);
}

int main(int argc, char** argv) {
    init();
    run_debug();
//    run_test();
//    test_generate();
//    test_solver();
    
//    normal_run();
//    double_solutions();
//    next_leaf_sorted();
//    direct_run();
//    test_scores();
//    test_scores_finals();
    return 0;
}

